home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / MagPLIP / source / device.c < prev    next >
C/C++ Source or Header  |  1998-04-01  |  25KB  |  828 lines

  1. /*
  2. ** $VER: device.c 1.13 (01 Apr 1998)
  3. **
  4. ** magplip.device - Parallel Line Internet Protocol
  5. **
  6. ** Original code written by Oliver Wagner and Michael Balzer.
  7. **
  8. ** This version has been completely reworked by Marius Gröger, introducing
  9. ** slight protocol changes. The new source is a lot better organized and
  10. ** maintainable.
  11. **
  12. ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
  13. ** The new source is significantly faster and yet better maintainable.
  14. **
  15. ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
  16. ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
  17. ** (C) Copyright 1995-1996 Marius Gröger
  18. **     All Rights Reserved
  19. **
  20. ** $HISTORY:
  21. **
  22. ** 01 Apr 1998 : 001.013 :  integrated linPLIP modifications from Stephane
  23. **                          by Stefan Ruppert <ruppert@amigaworld.com>
  24. ** 13 May 1996 : 001.012 :  unit wasn't dealt with properly,
  25. **                          fixed by Detlef Wuerkner <tetisoft@apg.lahn.de>
  26. ** 29 Mar 1996 : 001.011 :  changed copyright note
  27. ** 29 Dec 1995 : 001.010 :  + taglist of CreateNewProcTags() wasn't
  28. **                            properly ended
  29. **                          + FreeSignal() missing
  30. **                          + better error check on child task launch
  31. ** 03 Sep 1995 : 001.009 :  hardware addressing nicer
  32. ** 30 Aug 1995 : 001.008 :  minor declaration related changes
  33. ** 20 Aug 1995 : 001.007 :  just bumped for new header, no code changes
  34. ** 05 Aug 1995 : 001.006 :  finally compiles w/out warnings :)
  35. ** 25 Apr 1995 : 001.005 :  now compiles with ANSI and STRICT
  36. ** 08 Mar 1995 : 001.004 :  now handles directly write reqs, the server
  37. **                          task is just signalled
  38. ** 05 Mar 1995 : 001.003 :  S2_DEVICEQUERY was desastrously broken
  39. ** 04 Mar 1995 : 001.002 :  using SANA2IOF_QUICK instead IOF_QUICK
  40. ** 18 Feb 1995 : 001.001 :  using BASEPTR
  41. **                          PLIPBase is cleared in DevInit()
  42. **                          now rejects all r/w-requests without BuffMgmt
  43. ** 12 Feb 1995 : 001.000 :  reworked original
  44. */
  45.  
  46. #define DEBUG 0
  47.  
  48. /*F*/ /* includes */
  49. #ifndef CLIB_ALIB_PROTOS_H
  50. #include <clib/alib_protos.h>
  51. #endif
  52. #ifndef CLIB_EXEC_PROTOS_H
  53. #include <clib/exec_protos.h>
  54. #include <pragmas/exec_sysbase_pragmas.h>
  55. #endif
  56. #ifndef CLIB_DOS_PROTOS_H
  57. #include <clib/dos_protos.h>
  58. #include <pragmas/dos_pragmas.h>
  59. #endif
  60. #ifndef CLIB_CIA_PROTOS_H
  61. #include <clib/cia_protos.h>
  62. #include <pragmas/cia_pragmas.h>
  63. #endif
  64. #ifndef CLIB_MISC_PROTOS_H
  65. #include <clib/misc_protos.h>
  66. #include <pragmas/misc_pragmas.h>
  67. #endif
  68. #ifndef CLIB_UTILITY_PROTOS_H
  69. #include <clib/utility_protos.h>
  70. #include <pragmas/utility_pragmas.h>
  71. #endif
  72. #ifndef CLIB_TIME_PROTOS_H
  73. #include <clib/timer_protos.h>
  74. #include <pragmas/timer_pragmas.h>
  75. #endif
  76. #ifndef DEVICES_SANA2_H
  77. #include <devices/sana2.h>
  78. #endif
  79.  
  80. #ifndef HARDWARE_CIA_H
  81. #include <hardware/cia.h>
  82. #endif
  83.  
  84. #ifndef DOS_DOSTAGS_H
  85. #include <dos/dostags.h>
  86. #endif
  87.  
  88. #ifndef RESOURCES_MISC_H
  89. #include <resources/misc.h>
  90. #endif
  91.  
  92. #ifndef EXEC_MEMORY_H
  93. #include <exec/memory.h>
  94. #endif
  95.  
  96. #ifndef _STRING_H
  97. #include <string.h>
  98. #endif
  99.  
  100. #ifndef __MAGPLIP_H
  101. #include "magplip.h"
  102. #endif
  103. #ifndef __DEBUG_H
  104. #include "debug.h"
  105. #endif
  106. #ifndef __COMPILER_H
  107. #include "compiler.h"
  108. #endif
  109. /*E*/
  110.  
  111. /*F*/ /* imports */
  112. PUBLIC VOID SAVEDS ServerTask(VOID);
  113. PUBLIC BOOL remtracktype(BASEPTR, ULONG type);
  114. PUBLIC BOOL addtracktype(BASEPTR, ULONG type);
  115. PUBLIC BOOL gettrackrec(BASEPTR, ULONG type, struct Sana2PacketTypeStats *info);
  116. PUBLIC VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
  117. PUBLIC VOID freetracktypes(BASEPTR);
  118. #define min __builtin_min
  119. /*E*/
  120. /*F*/ /* exports */
  121. PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) BPTR seglist, REG(a6) struct Library *_SysBase);
  122. PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOSana2Req *ios2, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR);
  123. PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR);
  124. PUBLIC ASM SAVEDS BPTR DevClose( REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR);
  125. PUBLIC VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
  126. PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOSana2Req *ios2, REG(a6) BASEPTR);
  127. PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR);
  128. /*E*/
  129. /*F*/ /* private */
  130. PRIVATE BOOL isinlist(struct Node *n, struct List *l);
  131. PRIVATE VOID abort(BASEPTR, struct IOSana2Req *ior);
  132. /*E*/
  133.  
  134.    /*
  135.    ** various support routines
  136.    */
  137. /*F*/ PRIVATE BOOL isinlist(struct Node *n, struct List *l)
  138. {
  139.    struct Node *cmp;
  140.  
  141.    for(cmp = l->lh_Head; cmp->ln_Succ; cmp = cmp->ln_Succ)
  142.       if (cmp == n) return TRUE;
  143.    
  144.    return FALSE;
  145. }
  146. /*E*/
  147. /*F*/ PRIVATE VOID abort(BASEPTR, struct IOSana2Req *ior)
  148. {
  149.    Remove((struct Node*)ior);
  150.    ior->ios2_Req.io_Error = IOERR_ABORTED;
  151.    ior->ios2_WireError = 0;
  152.    ReplyMsg((struct Message*)ior);
  153. }
  154. /*E*/
  155.  
  156.    /*
  157.    ** initialise device
  158.    */
  159. /*F*/ PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) BPTR seglist, REG(a6) struct Library *_SysBase)
  160. {
  161.    BOOL ok;
  162.    UBYTE *p;
  163.    UWORD i;
  164.  
  165.    d(("entered device, initialising PLIPBase...\n"));
  166.  
  167.       /* clear data base */
  168.    for(p = ((UBYTE*)pb) + sizeof(struct Library), i = sizeof(struct PLIPBase)-sizeof(struct Library); i; i--)
  169.       *p++ = 0;
  170.  
  171.    SysBase = _SysBase;
  172.  
  173.    pb->pb_SegList = seglist;           /* store DOS segment list */
  174.  
  175.       /* init some default values */
  176.    pb->pb_MTU = PLIP_DEFMTU;
  177.    pb->pb_ReportBPS = PLIP_DEFBPS;
  178.    pb->pb_Retries = PLIP_DEFRETRIES;
  179.    pb->pb_Flags = PLIPF_NOTCONFIGURED | PLIPF_OFFLINE;
  180.    pb->pb_Timeout = PLIP_DEFTIMEOUT;
  181.  
  182.       /* set signal to unallocated state */
  183.    pb->pb_IntSig = (ULONG)-1;
  184.  
  185.       /* initialise the lists */
  186.    NewList((struct List*)&pb->pb_ReadList);
  187.    NewList((struct List*)&pb->pb_WriteList);
  188.    NewList((struct List*)&pb->pb_EventList);
  189.    NewList((struct List*)&pb->pb_ReadOrphanList);
  190.    NewList((struct List*)&pb->pb_TrackList);
  191.    NewList((struct List*)&pb->pb_BufferManagement);
  192.  
  193.       /* initialise the access protection semaphores */
  194.    InitSemaphore(&pb->pb_ReadListSem);
  195.    InitSemaphore(&pb->pb_ReadOrphanListSem);
  196.    InitSemaphore(&pb->pb_EventListSem);
  197.    InitSemaphore(&pb->pb_WriteListSem);
  198.    InitSemaphore(&pb->pb_TrackListSem);
  199.    InitSemaphore(&pb->pb_Lock);
  200.  
  201.    pb->pb_SpecialStats[S2SS_TXERRORS].Type = S2SS_PLIP_TXERRORS;
  202.    pb->pb_SpecialStats[S2SS_TXERRORS].Count = 0;
  203.    pb->pb_SpecialStats[S2SS_TXERRORS].String = "TX Errors";
  204.    pb->pb_SpecialStats[S2SS_COLLISIONS].Type = S2SS_PLIP_COLLISIONS;
  205.    pb->pb_SpecialStats[S2SS_COLLISIONS].Count = 0;
  206.    pb->pb_SpecialStats[S2SS_COLLISIONS].String = "Collisions";
  207.  
  208.    ok = FALSE;
  209.  
  210.    if (UtilityBase = OpenLibrary("utility.library", 37))
  211.    {
  212.       if (DOSBase = OpenLibrary("dos.library", 37))
  213.       {
  214.      ok = TRUE;
  215.       }
  216.       else
  217.       {
  218.      d(("no dos\n"));
  219.       }
  220.  
  221.       if (!ok) CloseLibrary(UtilityBase);
  222.    }
  223.    else
  224.    {
  225.       d(("no utility\n"));
  226.    }
  227.  
  228.    d(("left %ld\n",ok));
  229.  
  230.    return (struct Device *)(ok ? pb : NULL);
  231. }
  232. /*E*/
  233.  
  234.    /*
  235.    ** open device
  236.    */
  237. /*F*/ PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOSana2Req *ios2, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR)
  238. {
  239.    BOOL ok = FALSE;
  240.    struct BufferManagement *bm;
  241.    LONG rv;
  242.  
  243.    d(("entered\n"));
  244.  
  245.    /* Make sure our open remains single-threaded. */
  246.    ObtainSemaphore(&pb->pb_Lock);
  247.  
  248.    pb->pb_DevNode.lib_OpenCnt++;
  249.  
  250.    /* not promiscouos mode and unit valid ? */
  251.    if (!(flags & SANA2OPF_PROM) && ((unit == 0) || (unit == 1)))
  252.    {
  253.       /* Allow access only if NOT:
  254.       **
  255.       **    Anybody else has already opened it AND
  256.       **          the current access is exclusive
  257.       **       OR the first access was exclusive
  258.       **       OR this access wants a different unit
  259.       */
  260.  
  261.       if (!((pb->pb_DevNode.lib_OpenCnt > 1) &&
  262.         ((flags & SANA2OPF_MINE)
  263.       || (pb->pb_Flags & PLIPF_EXCLUSIVE)
  264.       || (unit != pb->pb_Unit))))
  265.       {
  266.      if (flags & SANA2OPF_MINE)
  267.         pb->pb_Flags |= PLIPF_EXCLUSIVE;
  268.      else
  269.         pb->pb_Flags &= ~PLIPF_EXCLUSIVE;
  270.      
  271.      /*
  272.      ** 13.05.96: Detlef Wuerkner <TetiSoft@apg.lahn.de>
  273.      ** Rememer unit of 1st OpenDevice()
  274.      */
  275.      if (pb->pb_DevNode.lib_OpenCnt == 1)
  276.         pb->pb_Unit = unit;
  277.  
  278. #ifndef LINPLIP
  279.      /*
  280.      ** The unit is ignored by linPLIP!
  281.      */
  282.  
  283.      /*
  284.      ** The origninal "client/server" scheme was unfortune. I guess this
  285.      ** resulted out of the (also very unfortune) wiring: POUT->POUT,
  286.      ** BUSY->BUSY. Had the creators chosen this connection to be crossed
  287.      ** over, a completely symmetrical driver would have been possible.
  288.      ** My new approach does the (in either case) neccessary crossing
  289.      ** by software. The PLIPBase->HandshakeXXX[] arrays are initialised
  290.      ** here so that the actual communication code are no longer bothered.
  291.      */
  292.      if (unit)
  293.      {
  294.         pb->pb_HandshakeMask[HS_LINE]    = CIAF_PRTRPOUT;
  295.         pb->pb_HandshakeMask[HS_REQUEST] = CIAF_PRTRBUSY;
  296.         pb->pb_HandshakeBit[HS_LINE]     = CIAB_PRTRPOUT;
  297.         pb->pb_HandshakeBit[HS_REQUEST]  = CIAB_PRTRBUSY;
  298.         pb->pb_SrcAddr[0] = 0x80;
  299.         pb->pb_DstAddr[0] = 0x00;
  300.      }
  301.      else
  302.      {
  303.         pb->pb_HandshakeMask[HS_LINE]    = CIAF_PRTRBUSY;
  304.         pb->pb_HandshakeMask[HS_REQUEST] = CIAF_PRTRPOUT;
  305.         pb->pb_HandshakeBit[HS_LINE]     = CIAB_PRTRBUSY;
  306.         pb->pb_HandshakeBit[HS_REQUEST]  = CIAB_PRTRPOUT;
  307.         pb->pb_SrcAddr[0] = 0x00;
  308.         pb->pb_DstAddr[0] = 0x80;
  309.      }
  310. #endif
  311.  
  312.      /*
  313.      ** Each opnener get's it's own BufferManagement. This is neccessary
  314.      ** since we want to allow several protocol stacks to use PLIP
  315.      ** simultaneously.
  316.      */
  317.      if (bm = AllocVec(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC))
  318.      {
  319.         /*
  320.         ** We don't care if there actually are buffer management functions,
  321.         ** because there might be openers who just want some statistics
  322.         ** from us.
  323.         */
  324. #if defined(__SASC) && (__VERSION__ == 6) && (__REVISION__ >= 56)
  325.         /* Jippieee! */
  326.         bm->bm_CopyToBuffer = (BMFunc)GetTagData(S2_CopyToBuff, NULL,
  327.                   (struct TagItem *)ios2->ios2_BufferManagement);
  328.         bm->bm_CopyFromBuffer = (BMFunc)GetTagData(S2_CopyFromBuff, NULL,
  329.                   (struct TagItem *)ios2->ios2_BufferManagement);
  330. #else
  331.         /*
  332.         ** The type casting below is very beautiful. This is a SAS/C bug:
  333.         ** I have to cast the ULONG that I got from GetTagData() to a
  334.         ** (void (*)(void)) function pointer. Now I may cast it to (BMFunc),
  335.         ** which defines the __asm and register stuff.
  336.         **
  337.         ** I would call this a cast with ``soft force'', as it seems that
  338.         ** I slowly have to make the ULONG being used to the fact of
  339.         ** becoming a pointer (``Look, old mathematical chap: didn't you
  340.         ** always want to be a pointer? Did you know how less it takes, how
  341.         ** mighty the dark side of the force really is?'').
  342.         */
  343.         bm->bm_CopyToBuffer = (BMFunc)((void (*)())(GetTagData(S2_CopyToBuff, NULL,
  344.                   (struct TagItem *)ios2->ios2_BufferManagement)));
  345.         bm->bm_CopyFromBuffer = (BMFunc)((void (*)())(GetTagData(S2_CopyFromBuff, NULL,
  346.                   (struct TagItem *)ios2->ios2_BufferManagement)));
  347. #endif
  348.         d(("starting servertask\n"));
  349.         if (!pb->pb_Server)
  350.         {
  351.            volatile struct ServerStartup ss;
  352.            struct MsgPort *port;
  353.  
  354.            if (port = CreateMsgPort())
  355.            {
  356.           d(("starting server"));
  357.           if (pb->pb_Server = CreateNewProcTags(NP_Entry, ServerTask, NP_Name,
  358.                                   SERVERTASKNAME, TAG_DONE))
  359.           {
  360.              ss.ss_Error = 1;
  361.              ss.ss_PLIPBase = pb;
  362.              ss.ss_Msg.mn_Length = sizeof(ss);
  363.              ss.ss_Msg.mn_ReplyPort = port;
  364.              d(("passing startup msg, pb is %lx\n", pb));
  365.              PutMsg(&pb->pb_Server->pr_MsgPort, (struct Message*)&ss);
  366.              WaitPort(port);
  367.  
  368.              if (!ss.ss_Error)
  369.             ok = TRUE;
  370.              else
  371.              {
  372.             d(("server task failed\n"));
  373.              }
  374.           }
  375.           else
  376.           {
  377.              d(("couldn't launch server task\n"));
  378.           }
  379.           DeleteMsgPort(port);
  380.            }
  381.            else
  382.            {
  383.           d(("no temp-message port for server startup\n"));
  384.            }
  385.         }
  386.         else ok = TRUE;
  387.  
  388.         if (!ok)
  389.            FreeVec(bm);
  390.         else
  391.         {
  392.            /* enqueue buffer management into list
  393.            */
  394.            AddTail((struct List *)&pb->pb_BufferManagement,(struct Node *)bm);
  395.            pb->pb_DevNode.lib_OpenCnt++;
  396.            pb->pb_DevNode.lib_Flags &= ~LIBF_DELEXP;
  397.            ios2->ios2_BufferManagement = (VOID *)bm;
  398.            ios2->ios2_Req.io_Error = 0;
  399.            ios2->ios2_Req.io_Unit = (struct Unit *)unit;
  400.            ios2->ios2_Req.io_Device = (struct Device *)pb;
  401.            rv = 0;
  402.         }
  403.      }
  404.       }
  405.    }
  406.  
  407.       /* See if something went wrong. */
  408.    if(!ok)
  409.    {
  410.       ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
  411.       ios2->ios2_Req.io_Unit = (struct Unit *) 0;
  412.       ios2->ios2_Req.io_Device = (struct Device *) 0;
  413.       rv = IOERR_OPENFAIL;
  414.    }
  415.    ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  416.  
  417.    pb->pb_DevNode.lib_OpenCnt--;
  418.    ReleaseSemaphore(&pb->pb_Lock);
  419.  
  420.    return rv;
  421. }
  422. /*E*/
  423.  
  424.    /*
  425.    ** close device
  426.    */
  427. /*F*/ PUBLIC ASM SAVEDS BPTR DevClose(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR)
  428. {
  429.    BPTR seglist;
  430.    struct BufferManagement *bm;
  431.  
  432.    d2(("entered\n"));
  433.  
  434.    ObtainSemaphore(&pb->pb_Lock);
  435.  
  436.       /* invalidate IO request block */
  437.    ior->ios2_Req.io_Device = (struct Device *)-1;
  438.    ior->ios2_Req.io_Unit = (struct Unit *)-1;
  439.  
  440.       /* search and free BuffMgmt structure */
  441.    for(bm = (struct BufferManagement *)pb->pb_BufferManagement.lh_Head;
  442.        bm->bm_Node.mln_Succ; bm = (struct BufferManagement *)bm->bm_Node.mln_Succ)
  443.       if (bm == ior->ios2_BufferManagement)
  444.       {
  445.      Remove((struct Node*)bm);
  446.      FreeVec(bm);
  447.      break;
  448.       }
  449.  
  450.    pb->pb_DevNode.lib_OpenCnt--;
  451.  
  452.    ReleaseSemaphore(&pb->pb_Lock);
  453.  
  454.    if (pb->pb_DevNode.lib_Flags & LIBF_DELEXP)
  455.       seglist = DevExpunge(pb);
  456.    else
  457.       seglist = 0;
  458.  
  459.    return seglist;
  460. }
  461. /*E*/
  462.  
  463.  
  464. /*F*/ PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR)
  465. {
  466.    BPTR seglist;
  467.    ULONG sigb;
  468.  
  469.    d2(("entered\n"));
  470.  
  471.    if (pb->pb_DevNode.lib_OpenCnt)
  472.    {
  473.       pb->pb_DevNode.lib_Flags |= LIBF_DELEXP;
  474.       seglist = 0;
  475.    }
  476.    else
  477.    {
  478.      /* detach device from system list */
  479.       Remove((struct Node*)pb);
  480.  
  481.      /* stop the servr task */
  482.       d2(("killing server task\n"));
  483.       pb->pb_Task = FindTask(0L);
  484.      /* We must allocate a new signal, as we don't know in whose
  485.      ** context we're running. If we get no signal, we poll
  486.      ** for the server-exits flag.
  487.      */
  488.       sigb = AllocSignal(-1);
  489.       pb->pb_ServerStoppedSigMask = (sigb == -1) ? 0 : (1<<sigb);
  490.       Signal((struct Task*)pb->pb_Server, SIGBREAKF_CTRL_C);
  491.       if (pb->pb_ServerStoppedSigMask)
  492.       {
  493.      Wait(pb->pb_ServerStoppedSigMask);
  494.      FreeSignal(sigb);
  495.       }
  496.       else
  497.       {
  498.      while(!(pb->pb_Flags & PLIPF_SERVERSTOPPED))
  499.         Delay(10);
  500.       }
  501.       d2(("server task has gone\n"));
  502.  
  503.      /* clean up track */
  504.       freetracktypes(pb);
  505.  
  506.       CloseLibrary(UtilityBase);
  507.       CloseLibrary(DOSBase);
  508.  
  509.      /* save seglist for return value */
  510.       seglist = (long)pb->pb_SegList;
  511.  
  512.      /* return memory
  513.      **
  514.      ** NO FURTHER ACCESS TO PLIPBase ALLOWED!
  515.      */
  516.       FreeMem( ((char *) pb) - pb->pb_DevNode.lib_NegSize,
  517.      (ULONG)(pb->pb_DevNode.lib_PosSize + pb->pb_DevNode.lib_NegSize));
  518.    }
  519.  
  520.    return seglist;
  521. }
  522. /*E*/
  523.  
  524.    /*
  525.    ** initiate io command (1st level dispatcher)
  526.    */
  527. /*F*/ static INLINE VOID DevForwardIO(BASEPTR, struct IOSana2Req *ios2)
  528. {
  529.    d(("forwarding request %ld\n", ios2->ios2_Req.io_Command));
  530.  
  531.    /* request is no longer of type "quick i/o" */
  532.    ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  533.    PutMsg(pb->pb_ServerPort, (struct Message*)ios2);
  534. }
  535. /*E*/
  536. /*F*/ PUBLIC VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2)
  537. {
  538.    d(("cmd = %ld, error = %ld, wireerror = %ld\n", ios2->ios2_Req.io_Command, ios2->ios2_Req.io_Error,ios2->ios2_WireError));
  539.  
  540.           /* if this command was done asynchonously, we must
  541.           ** reply the request
  542.           */
  543.    if(!(ios2->ios2_Req.io_Flags & SANA2IOF_QUICK))
  544.       ReplyMsg((struct Message *)ios2);
  545.    else           /* otherwise just mark it as done */
  546.       ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  547. }
  548. /*E*/
  549. /*F*/ PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOSana2Req *ios2, REG(a6) BASEPTR)
  550. {
  551.       /* mark request as active */
  552.    ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  553.    ios2->ios2_Req.io_Error = S2ERR_NO_ERROR;
  554.    ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  555.  
  556.    d(("cmd = %ld\n",ios2->ios2_Req.io_Command));
  557.  
  558.       /*
  559.       ** 1st level command dispatcher
  560.       **
  561.       ** Here we decide wether we can process the request immediately avoiding
  562.       ** a task switch. This is called "Quick I/O" and signalled to DoIO()
  563.       ** by setting the node type of the request to NT_REPLYMSG (see TermIO()).
  564.       **
  565.       ** Otherwise, we clear the SANA2IOF_QUICK flag and forward the request to
  566.       ** the server. We may NEVER again access the request structure after
  567.       ** the PutMsg()! The server - running at a high priority - will peempt
  568.       ** us and might complety satisfy the request before we will be wakened up
  569.       ** again.
  570.       ** The same goes for those requests that we put into the server's queue.
  571.       */
  572.    switch(ios2->ios2_Req.io_Command)
  573.    {
  574.       case CMD_READ:
  575.      if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  576.      {
  577.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  578.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  579.      }
  580.      else if (ios2->ios2_BufferManagement == NULL)
  581.      {
  582.         ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  583.         ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  584.      }
  585.      else
  586.      {
  587.         ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  588.         ObtainSemaphore(&pb->pb_ReadListSem);
  589.         AddTail((struct List*)&pb->pb_ReadList, (struct Node*)ios2);
  590.         ReleaseSemaphore(&pb->pb_ReadListSem);
  591.         ios2 = NULL;
  592.      }
  593.       break;
  594.  
  595.       case CMD_WRITE:
  596.       case S2_BROADCAST:
  597.      if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
  598.      {
  599.         ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  600.         ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  601.      }
  602.      else if(ios2->ios2_DataLength > pb->pb_MTU)
  603.      {
  604.         ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
  605.      }
  606.      else if (ios2->ios2_BufferManagement == NULL)
  607.      {
  608.         ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  609.         ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  610.      }
  611.      else if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  612.      {
  613.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  614.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  615.      }
  616.      else
  617.      {
  618.         ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  619.         ios2->ios2_Req.io_Error = 0;
  620.         ObtainSemaphore(&pb->pb_WriteListSem);
  621.         AddTail((struct List*)&pb->pb_WriteList, (struct Node*)ios2);
  622.         ReleaseSemaphore(&pb->pb_WriteListSem);
  623.         Signal((struct Task*)pb->pb_Server, SIGBREAKF_CTRL_F);
  624.         ios2 = NULL;
  625.      }
  626.       break;
  627.  
  628.       case S2_ONLINE:
  629.       case S2_OFFLINE:
  630.       case S2_CONFIGINTERFACE:   /* forward request */
  631.      DevForwardIO(pb, ios2);
  632.      ios2 = NULL;
  633.       break;
  634.  
  635.       case S2_GETSTATIONADDRESS:
  636. #ifndef LINPLIP
  637.      /*
  638.      ** linPLIP doesn't care for adresses (yet).
  639.      */
  640.  
  641.      memcpy(ios2->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  642.      memcpy(ios2->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  643. #endif
  644.       break;
  645.      
  646.       case S2_DEVICEQUERY:
  647.       {
  648.      struct Sana2DeviceQuery *devquery;
  649.  
  650.      devquery = ios2->ios2_StatData;
  651.      devquery->DevQueryFormat = 0;        /* "this is format 0" */
  652.      devquery->DeviceLevel = 0;           /* "this spec defines level 0" */
  653.      
  654.      if (devquery->SizeAvailable >= 18) devquery->AddrFieldSize = PLIP_ADDRFIELDSIZE;
  655.      if (devquery->SizeAvailable >= 22) devquery->MTU           = pb->pb_MTU;
  656.      if (devquery->SizeAvailable >= 26) devquery->BPS           = pb->pb_ReportBPS;
  657.      if (devquery->SizeAvailable >= 30) devquery->HardwareType  = S2WireType_PLIP;
  658.      
  659.      devquery->SizeSupplied = min((int)devquery->SizeAvailable, 30);
  660.       }
  661.       break;
  662.      
  663.       case S2_ONEVENT:
  664.      /* Two special cases. S2EVENT_ONLINE and S2EVENT_OFFLINE are supposed to
  665.         retun immediately if we are already in the state that they are waiting
  666.         for. */
  667.      if (((ios2->ios2_WireError & S2EVENT_ONLINE) && !(pb->pb_Flags & PLIPF_OFFLINE)) ||
  668.          ((ios2->ios2_WireError & S2EVENT_OFFLINE) && (pb->pb_Flags & PLIPF_OFFLINE)))
  669.      {
  670.         ios2->ios2_Req.io_Error = 0;
  671.         ios2->ios2_WireError &= (S2EVENT_ONLINE|S2EVENT_OFFLINE);
  672.         DevTermIO(pb,ios2);
  673.         ios2 = NULL;
  674.      }
  675.      else if ((ios2->ios2_WireError & (S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE|
  676.                    S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE|S2EVENT_SOFTWARE))
  677.           != ios2->ios2_WireError)
  678.      {
  679.         /* we cannot handle such events */
  680.         ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  681.         ios2->ios2_WireError = S2WERR_BAD_EVENT;
  682.      }
  683.      else
  684.      {
  685.         /* Queue anything else */
  686.         ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  687.         ObtainSemaphore(&pb->pb_EventListSem);
  688.         AddTail((struct List*)&pb->pb_EventList, (struct Node*)ios2);
  689.         ReleaseSemaphore(&pb->pb_EventListSem);
  690.         ios2 = NULL;
  691.      }
  692.       break;
  693.  
  694.       /* --------------- stats support ----------------------- */
  695.  
  696.       case S2_TRACKTYPE:
  697.      if (!addtracktype(pb, ios2->ios2_PacketType))
  698.      {
  699.         ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  700.      }
  701.       break;
  702.  
  703.       case S2_UNTRACKTYPE:
  704.      if (!remtracktype(pb, ios2->ios2_PacketType))
  705.      {
  706.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  707.         ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  708.      }
  709.       break;
  710.  
  711.       case S2_GETTYPESTATS:
  712.      if (!gettrackrec(pb, ios2->ios2_PacketType, (struct Sana2PacketTypeStats *)ios2->ios2_StatData))
  713.      {
  714.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  715.         ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  716.      }
  717.       break;
  718.  
  719.       case S2_READORPHAN:
  720.      if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  721.      {
  722.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  723.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  724.      }
  725.      else if (ios2->ios2_BufferManagement == NULL)
  726.      {
  727.         ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  728.         ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  729.      }
  730.      else
  731.      {                       /* Enqueue it to the orphan-reader-list */
  732.         ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  733.         ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  734.         AddTail((struct List*)&pb->pb_ReadOrphanList, (struct Node*)ios2);
  735.         ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  736.         ios2 = NULL;
  737.      }
  738.       break;
  739.  
  740.       case S2_GETGLOBALSTATS:
  741.      memcpy(ios2->ios2_StatData, &pb->pb_DevStats, sizeof(struct Sana2DeviceStats));
  742.       break;
  743.  
  744.       case S2_GETSPECIALSTATS:
  745.       {
  746.      struct Sana2SpecialStatHeader *s2ssh = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
  747.  
  748.      if (pb->pb_ExtFlags & PLIPEF_NOSPECIALSTATS)
  749.      {
  750.         s2ssh->RecordCountSupplied = 0;
  751.      }
  752.      else
  753.      {
  754.         s2ssh->RecordCountSupplied = s2ssh->RecordCountMax > S2SS_COUNT ?
  755.                       S2SS_COUNT : s2ssh->RecordCountMax;
  756.         CopyMem(pb->pb_SpecialStats, (void*)(s2ssh+1),
  757.             s2ssh->RecordCountSupplied*sizeof(struct Sana2SpecialStatRecord));
  758.      }
  759.       }
  760.       break;
  761.  
  762.       /* --------------- unsupported requests -------------------- */
  763.  
  764.      /* all standard commands we don't support */
  765.       case CMD_RESET:
  766.       case CMD_UPDATE:
  767.       case CMD_CLEAR:
  768.       case CMD_STOP:
  769.       case CMD_START:
  770.       case CMD_FLUSH:
  771.      ios2->ios2_Req.io_Error = IOERR_NOCMD;
  772.      ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  773.       break;
  774.  
  775.      /* other commands (SANA-2) we don't support */
  776.       /*case S2_ADDMULTICASTADDRESS:*/
  777.       /*case S2_DELMULTICASTADDRESS:*/
  778.       /*case S2_MULTICAST:*/
  779.       default:
  780.      ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  781.      ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  782.       break;
  783.    }
  784.  
  785.    if (ios2) DevTermIO(pb, ios2);
  786.  
  787.    return;
  788. }
  789. /*E*/
  790.  
  791.    /*
  792.    ** stop io-command
  793.    */
  794. /*F*/ PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOSana2Req *ior, REG(a6) BASEPTR)
  795. {
  796.    BOOL is;
  797.    LONG rc = 0;
  798.  
  799.    d(("cmd = %ld\n",ior->ios2_Req.io_Command));
  800.  
  801.    ObtainSemaphore(&pb->pb_WriteListSem);
  802.    if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_WriteList)) abort(pb,ior);
  803.    ReleaseSemaphore(&pb->pb_WriteListSem);
  804.    if (is) goto leave;
  805.  
  806.    ObtainSemaphore(&pb->pb_ReadListSem);
  807.    if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_ReadList)) abort(pb,ior);
  808.    ReleaseSemaphore(&pb->pb_ReadListSem);
  809.    if (is) goto leave;
  810.  
  811.    ObtainSemaphore(&pb->pb_EventListSem);
  812.    if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_EventList)) abort(pb,ior);
  813.    ReleaseSemaphore(&pb->pb_EventListSem);
  814.    if (is) goto leave;
  815.  
  816.    ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  817.    if (is = isinlist((struct Node*)ior, (struct List*)&pb->pb_ReadOrphanList)) abort(pb,ior);
  818.    ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  819.    if (is) goto leave;
  820.  
  821.    rc = -1;
  822.  
  823. leave:
  824.    return rc;
  825. }
  826. /*E*/
  827.  
  828.